package com.inspur.edp.common.expr.compile;

import com.inspur.edp.common.expr.exception.ExpressException;
import org.codehaus.commons.compiler.util.ResourceFinderClassLoader;
import org.codehaus.commons.compiler.util.resource.MapResourceCreator;
import org.codehaus.commons.compiler.util.resource.MapResourceFinder;
import org.codehaus.commons.compiler.util.resource.Resource;
import org.codehaus.commons.compiler.util.resource.StringResource;
import org.codehaus.janino.ClassLoaderIClassLoader;
import org.codehaus.janino.Compiler;
import org.codehaus.janino.CompilerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author lizhaorui
 * @date 2025/8/15
 * @description
 */
public class JavaCompileService {

    private static final CompilerFactory compilerFactory = new CompilerFactory();

    public ClassLoader compile(List<JavaSourceCode> sourceCodes) {
        try {
            Compiler compiler = (Compiler) compilerFactory.newCompiler();
            Map<String, byte[]> classes = new HashMap<>();
            compiler.setClassFileCreator(new MapResourceCreator(classes));
            compiler.setIClassLoader(new ClassLoaderIClassLoader(JavaCompileService.class.getClassLoader()));
            Resource[] resources = new Resource[sourceCodes.size()];
            for (int i = 0; i < sourceCodes.size(); i++) {
                JavaSourceCode sourceCode = sourceCodes.get(i);
                resources[i] = new StringResource(sourceCode.getClassFullName(), sourceCode.getSourceCode());
            }
            compiler.compile(resources);
            return new ResourceFinderClassLoader(
                    new MapResourceFinder(classes),
                    JavaCompileService.class.getClassLoader()
            );
        } catch (Throwable ex) {
            throw new ExpressException(String.format("compile express occur error: %s ，java code: [%s]", ex.getMessage(), getAllCode(sourceCodes)), ex);
        }
    }

    private String getAllCode(List<JavaSourceCode> sourceCodes) {
        if (sourceCodes == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (JavaSourceCode sourceCode : sourceCodes) {
            sb.append("\n" + sourceCode.getSourceCode());
        }
        return sb.toString();
    }

}